#include "ObjectController.h"
#include <stdio.h>
#include <stdlib.h>
#include "Logger.h"
#include "../OpenGL.h"
#include "Camera.h"

ObjectController objectController;

ObjectController::ObjectController(){
    numberOfInstances=0;
    nextInstanceId=0;
    list=0;
    cameras=0;
    numberOfCameras=0;
}
ObjectController::~ObjectController(){
    if (list!=0){free(list);}
}
void				ObjectController::resize(){
    if (list==0){list=(Object**)malloc(numberOfInstances*sizeof(Object));}
    else if (numberOfInstances==0){free(list);list=0;}
    else{list=(Object**)realloc(list,numberOfInstances*sizeof(Object));}
}
void				ObjectController::resizeCameras(){
    if (cameras==0){cameras=(Camera**)malloc(numberOfInstances*sizeof(Camera));}
    else if (numberOfInstances==0){free(list);list=0;}
    else{cameras=(Camera**)realloc(cameras,numberOfInstances*sizeof(Camera));}
}
Object*				ObjectController::create(Object *obj){
    //create(new Object());
    nextInstanceId++;
    numberOfInstances++;
    resize();
    list[numberOfInstances-1]=obj;
    list[numberOfInstances-1]->__setId(nextInstanceId);//this is where id comes from
    list[numberOfInstances-1]->create();
    return list[numberOfInstances-1];
}
Object*				ObjectController::createCamera(Camera *cam){
    Object *ret;
    ret = create(cam);
    numberOfCameras++;
    resizeCameras();
    cameras[numberOfCameras-1]=cam;
    return ret;
}
ObjectController&	ObjectController::destroy(Object *obj){
    long i,ii;
    //we need to check our list from last to first to find if we have obj
    for (i=numberOfInstances-1;i>=0;i--)
    {
        //if we found obj...
        if (list[i]==obj)
        {
            list[i]->destroyed();
            delete list[i];
            list[i]=0;
            //we need to start shifting the pointers down to fill in
            for (ii=i;i<numberOfInstances-1;i++)
            {
                //this is the shifting process... not too exciting
                list[ii]=list[ii+1];
            }
            //we have one less object now
            numberOfInstances--;
        }
    }
    resize();//make sure we do not have bad space
    for (i=numberOfCameras-1;i>=0;i--)
    {
        if (cameras[i]==obj)
        {
            //already called destroyed
            delete cameras[i];
            cameras[i]=0;
            for (ii=i;i<numberOfCameras-1;i++)
            {
                cameras[ii]=cameras[ii+1];
            }
            numberOfCameras--;
        }
    }
    return *this;
}
INSTANCE_ID			ObjectController::getNumberOfInstances(){
    return numberOfInstances;
}
INSTANCE_ID			ObjectController::getNumberOfCameras(){
    return numberOfCameras;
}
ObjectController&	ObjectController::step(){
    for (int i=0; i<numberOfInstances; i++)
    {
        list[i]->step();
    }
    return *this;
}
ObjectController&	ObjectController::draw(){
    for (int i=0;i<numberOfInstances;i++)
    {
        list[i]->draw();
    }
    return *this;
}
ObjectController&	ObjectController::drawOrtho(){
    for (int i=0;i<numberOfInstances;i++)
    {
        list[i]->drawOrtho();
    }
    return *this;
}
ObjectController&	ObjectController::cameraSetup(){
    for (int i=0;i<numberOfCameras;i++)
    {
        cameras[i]->__cameraSetup();
    }
    return *this;
}
ObjectController&	ObjectController::collisions(){
    //fun stuff
    return *this;
}
ObjectController&	ObjectController::mouseConst(double x, double y){
    mouse.set(x,y);
    //mouseState[button]=true;
    for (int i=0;i<=3;i++)
    {
        if (mouseState[i])
        {
            for (int i=0;i<numberOfInstances;i++)
            {
                list[i]->globalMouse(i,mouse);
            }
        }
    }
    return *this;
}
ObjectController&	ObjectController::mouseDown(int button, double x, double y){
    if (button>3){return *this;}
    mouseState[button]=true;
    for (int i=0;i<numberOfInstances;i++)
    {
        list[i]->globalMouseDown(button,Point2D().set(x,y));
    }
    return *this;
}
ObjectController&	ObjectController::mouseUp(int button, double x, double y){
    if (button>3){return *this;}
    mouseState[button]=false;
    for (int i=0;i<numberOfInstances;i++)
    {
        list[i]->globalMouseUp(button,Point2D().set(x,y));
    }
    return *this;
}
ObjectController&	ObjectController::key(int button){
    if (button>255){return *this;}
    keyState[lowerKey(button)]=true;
    for (int i=0;i<numberOfInstances;i++)
    {
        list[i]->key(button);
    }
    return *this;
}
ObjectController&	ObjectController::keyDown(int button){
    if (button>255){return *this;}
    //keyState[button]=true;
    for (int i=0;i<numberOfInstances;i++)
    {
        list[i]->keyDown(button);
    }
    return *this;
}
ObjectController&	ObjectController::keyUp(int button){
    if (button>255){return *this;}
    keyState[lowerKey(button)]=false;
    for (int i=0;i<numberOfInstances;i++)
    {
        list[i]->keyUp(button);
    }
    return *this;
}
ObjectController&	ObjectController::specialKey(int button){
    int mappedKey;
	mappedKey = mapSpecialKey(button);
	if (!getKeyState(mappedKey)){keyDown(mappedKey);}
	key(mappedKey);
    return *this;
}
ObjectController&	ObjectController::specialKeyUp(int button){
	keyUp(mapSpecialKey(button));
	return *this;
}
bool				ObjectController::getKeyState(char key){
    //if (key>255){return false;}
    return keyState[(int)key];
}
bool				ObjectController::getMouseState(char key){
    if (key>3){return false;}
    return mouseState[(int)key];
}
Point2D&			ObjectController::getMousePosition(){
    return mouse;
}
int					ObjectController::mapSpecialKey(int key){
	switch (key)
    {
        case GLUT_KEY_F1:return KEY_F1;
        case GLUT_KEY_F2:return KEY_F2;
        case GLUT_KEY_F3:return KEY_F3;
        case GLUT_KEY_F4:return KEY_F4;
        case GLUT_KEY_F5:return KEY_F5;
        case GLUT_KEY_F6:return KEY_F6;
        case GLUT_KEY_F7:return KEY_F7;
        case GLUT_KEY_F8:return KEY_F8;
        case GLUT_KEY_F9:return KEY_F9;
        case GLUT_KEY_F10:return KEY_F10;
        case GLUT_KEY_F11:return KEY_F11;
        case GLUT_KEY_F12:return KEY_F12;
        case GLUT_KEY_LEFT:return KEY_LEFT;
        case GLUT_KEY_RIGHT:return KEY_RIGHT;
        case GLUT_KEY_UP:return KEY_UP;
        case GLUT_KEY_DOWN:return KEY_DOWN;
        case GLUT_KEY_PAGE_UP:return KEY_PAGE_UP;
        case GLUT_KEY_PAGE_DOWN:return KEY_PAGE_DOWN;
        case GLUT_KEY_HOME:return KEY_HOME;
        case GLUT_KEY_END:return KEY_END;
        case GLUT_KEY_INSERT:return KEY_INSERT;
        default:return key;
    }
}
int					ObjectController::lowerKey(int key){
	if (key>=(int)'A' && key<=(int)'Z')
	{
		return key|0x20;
	}
	return key;
}
